package com.tencent.wxpay.business;

import com.tencent.wxpay.businessListener.BaseResultListener;
import com.tencent.wxpay.common.Configure;
import com.tencent.wxpay.common.Signature;
import com.tencent.wxpay.common.Util;
import com.tencent.wxpay.common.report.ReporterFactory;
import com.tencent.wxpay.common.report.protocol.ReportReqData;
import com.tencent.wxpay.common.report.service.ReportService;
import com.tencent.wxpay.protocol.request.UnifiedOrderReqData;
import com.tencent.wxpay.protocol.response.UnifiedOrderResData;
import com.tencent.wxpay.service.UnifiedOrderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 统一下单服务
 */
public class UnifiedOrderBusiness {

    private static Logger logger = LoggerFactory.getLogger(UnifiedOrderBusiness.class);

    /**
     * 运行统一下单服务
     * @param unifiedOrderReqData 这个数据对象里面包含了API要求提交的各种数据字段
     * @param resultListener 返回结果的监听接口
     * @return UnifiedOrderResData 结果对象
     * @throws Exception
     */
    public static UnifiedOrderResData run(UnifiedOrderReqData unifiedOrderReqData, BaseResultListener<UnifiedOrderResData> resultListener) throws Exception {
        //--------------------------------------------------------------------
        //构造请求“统一下单API”所需数据
        //--------------------------------------------------------------------
        UnifiedOrderService unifiedOrderService = new UnifiedOrderService();
        // 商户订单号
        String outTradeNo = unifiedOrderReqData.getOut_trade_no();
        //接收API返回值
        String unifiedOrderServiceRes;
        // API调用开始时间
        long costTimeStart = System.currentTimeMillis();
        // 发起请求
        unifiedOrderServiceRes = unifiedOrderService.request(unifiedOrderReqData);
        // API调用结束时间
        long costTimeEnd = System.currentTimeMillis();
        // API请求耗费时间
        long totalTimeCost = costTimeEnd - costTimeStart;
        logger.info("统一下单接口,【订单号："+outTradeNo+"】请求总耗时：" + totalTimeCost + "ms");

        //打印回包数据
        logger.info("统一下单接口,【订单号："+outTradeNo+"】 回包数据:");
        logger.info(unifiedOrderServiceRes);

        //将从API返回的XML数据映射到Java对象
        UnifiedOrderResData unifiedOrderResData = (UnifiedOrderResData) Util.getObjectFromXML(unifiedOrderServiceRes, UnifiedOrderResData.class);

        //是否发送统计请求
        if(Configure.isReport()) {
            ReportReqData reportReqData = new ReportReqData(
                unifiedOrderReqData.getDevice_info(),
                Configure.UNIFIED_ORDER_API,
                (int) (totalTimeCost),//本次请求耗时
                unifiedOrderResData.getReturn_code(),
                unifiedOrderResData.getReturn_msg(),
                unifiedOrderResData.getResult_code(),
                unifiedOrderResData.getErr_code(),
                unifiedOrderResData.getErr_code_des(),
                outTradeNo,
                unifiedOrderReqData.getSpbill_create_ip()
            );
            // unifiedOrder+report总耗时
            long timeAfterReport;
            // 判断是否异步发送
            if (Configure.isUseThreadToDoReport()) {
                ReporterFactory.getReporter(reportReqData).run();
                timeAfterReport = System.currentTimeMillis();
                logger.info("【订单号："+outTradeNo+"】unifiedOrder+report总耗时（异步方式上报）：" + (timeAfterReport - costTimeStart) + "ms");
            } else {
                ReportService.request(reportReqData);
                timeAfterReport = System.currentTimeMillis();
                logger.info("【订单号："+outTradeNo+"】unifiedOrder+report总耗时（同步方式上报）：" + (timeAfterReport - costTimeStart) + "ms");
            }

        }
        // API通信失败
        if (unifiedOrderResData == null || unifiedOrderResData.getReturn_code() == null) {
            logger.error("【下单失败】【订单号："+outTradeNo+"】下单请求逻辑错误，请仔细检测传过去的每一个参数是否合法，或是看API能否被正常访问");
            resultListener.onFailByReturnCodeError(unifiedOrderResData);
            return unifiedOrderResData;
        }
        // API通信成功，但调用出错，可能签名失败或参数格式校验错误
        if (unifiedOrderResData.getReturn_code().equals("FAIL")) {
            //注意：一般这里返回FAIL是出现系统级参数错误，请检测Post给API的数据是否规范合法
            logger.error("【下单失败】【订单号："+outTradeNo+"】下单API系统返回失败，请检测Post给API的数据是否规范合法");
            resultListener.onFailByReturnCodeFail(unifiedOrderResData);
            return unifiedOrderResData;
        } else {
            // API通信成功，调用接口成功，有返回数据,但业务不一定执行成功
            logger.info("统一下单接口【订单号："+outTradeNo+"】成功返回数据");
            //--------------------------------------------------------------------
            //收到API的返回数据的时候得先验证一下数据有没有被第三方篡改，确保安全
            //--------------------------------------------------------------------
            if (!Signature.checkIsSignValidFromResponseString(unifiedOrderServiceRes)) {
                logger.error("【支付失败】【订单号："+outTradeNo+"】支付请求API返回的数据签名验证失败，有可能数据被篡改了");
                resultListener.onFailBySignInvalid(unifiedOrderResData);
                return unifiedOrderResData;
            }

            if (unifiedOrderResData.getResult_code().equals("SUCCESS")) {
                //--------------------------------------------------------------------
                //下单成功
                //--------------------------------------------------------------------
                logger.info("【下单成功】【订单号："+outTradeNo+"】");
                resultListener.onSuccess(unifiedOrderResData);
            } else {
                //出现业务错误
                logger.error("【下单失败】【订单号："+outTradeNo+"】");
                logger.error("错误码:" + unifiedOrderResData.getErr_code());
                logger.error("错误描述:" + unifiedOrderResData.getErr_code_des());
                //业务错误都走onFail接口方法，请接口实现者自行处理
                resultListener.onFail(unifiedOrderResData);
            }
        }
        return unifiedOrderResData;
    }
}
